package cn.com.jdyun.service.impl;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import cn.com.jdyun.mapper.ext.ExtSysConfigMapper;
import cn.com.jdyun.pojo.SysConfig;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;

import cn.com.jdyun.dto.TransferRecordsDTO;
import cn.com.jdyun.exception.BdexGatewayException;
import cn.com.jdyun.mapper.TransferRecordsMapper;
import cn.com.jdyun.mapper.ext.ExtUserWalletMapper;
import cn.com.jdyun.pojo.TransferRecords;
import cn.com.jdyun.pojo.User;
import cn.com.jdyun.pojo.UserWallet;
import cn.com.jdyun.service.LockCoinService;
import cn.com.jdyun.service.LotteryService;
import cn.com.jdyun.service.MessageService;
import cn.com.jdyun.service.RefereeService;
import cn.com.jdyun.service.SysConfigService;
import cn.com.jdyun.service.TransferService;
import cn.com.jdyun.service.UserSecService;
import cn.com.jdyun.service.UserService;
import cn.com.jdyun.service.UserWalletService;
import cn.com.jdyun.util.ConfigParam;
import cn.com.jdyun.util.Constant;
import cn.com.jdyun.util.RedisUtil;
import cn.com.jdyun.util.SnowflakeIdWorker;

/**
 * @author yzping
 * @date Created in 下午 2:16 2018/8/25 0025
 */
@Service
public class TransferServiceImpl implements TransferService {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TransferServiceImpl.class);
    @Autowired
    UserWalletService userWalletService;
    @Autowired
    TransferRecordsMapper transferRecordsMapper;
    @Autowired
    RefereeService refereeService;
    @Autowired
    ExtUserWalletMapper walletMapper;
    @Autowired
    LockCoinService lockCoinService;
    @Autowired
    LotteryService lotteryService;
    @Autowired
    UserSecService userSecService;
    @Autowired
    UserService userService;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    SysConfigService sysConfigService;
    @Autowired
    MessageService messageService;
    @Autowired
    ExtSysConfigMapper sysConfigMapper;

    @Autowired
    ExtUserWalletMapper userWalletMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public TransferRecords transferFrom(String from, String to, String coinType, String amount, String secPassword, String receivePhone, String remarks) throws BdexGatewayException, UnsupportedEncodingException {

        if (StringUtils.isEmpty(coinType)) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 币种不能为空!" );
            throw new BdexGatewayException("币种不能为空!");
        }
        if (StringUtils.isEmpty(amount)) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 转账的数量不能为空!" );
            throw new BdexGatewayException("转账的数量不能为空!");
        }
        if (StringUtils.isEmpty(from)) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 转出方的id不能为空!" );
            throw new BdexGatewayException("转出方的id不能为空!");
        }
        if (StringUtils.isEmpty(to)) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 转入方的id不能为空!" );
            throw new BdexGatewayException("转入方的id不能为空!");
        }
        if (StringUtils.isEmpty(secPassword)) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 交易密码不能为空!" );
            throw new BdexGatewayException("交易密码不能为空!");
        }

        BigDecimal serviceCharge = new BigDecimal("0");
        BigDecimal transferAmount;
        //查询转出方的代币余额够不够
        UserWallet fromWallet = userWalletService.queryByUserIdAndConiType(from, coinType);
        //转出方的钱包代币数量
        BigDecimal fromAmount = new BigDecimal(fromWallet.getBalance());
        transferAmount = new BigDecimal(amount);
        //手续费千分之二
        if(Constant.COINTYPE_TEX.equals(coinType)){
            SysConfig serviceChargeConfig = sysConfigMapper.selectByCode(Constant.serviceCharge);
            serviceCharge = transferAmount.multiply(new BigDecimal(serviceChargeConfig.getInitValue()));
        }else if(Constant.COINTYPE_SSSP.equals(coinType)){
            SysConfig serviceTEXChargeConfig = sysConfigMapper.selectByCode(Constant.serviceTEXCharge);
            serviceCharge = transferAmount.multiply(new BigDecimal(serviceTEXChargeConfig.getInitValue()));
        }else if(Constant.CANDY.equals(coinType)){
            serviceCharge = new BigDecimal("0");
        }else{
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+" 转账代币类型错误!" );
            throw new BdexGatewayException("转账代币类型错误!");
        }
        if (fromAmount.compareTo(transferAmount.add(serviceCharge)) < 0) {
            logger.error(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+":您钱包" + coinType + "币数量不足,请确认!");
            throw new BdexGatewayException("您钱包" + coinType + "币数量不足,请确认!");
        }

        fromAmount = fromAmount.subtract(serviceCharge).subtract(transferAmount);
        fromWallet.setAsset(new BigDecimal(fromWallet.getAsset()).subtract(serviceCharge).subtract(transferAmount) + "");
        fromWallet.setBalance(fromAmount + "");
        fromWallet.setCreateTime(new Date());
        userWalletService.updateWallet(fromWallet);

        TransferRecords record = new TransferRecords(
                SnowflakeIdWorker.generateId(),
                (byte) 0,
                amount,
                serviceCharge + "",
                coinType,
                from,
                to,
                remarks,
                new Date());
        transferRecordsMapper.insert(record);

        //修改收账账户钱包：
        UserWallet toCoinAmountInfo = userWalletService.queryByUserIdAndConiType(to, coinType);
        BigDecimal toCoinAmount = new BigDecimal(toCoinAmountInfo.getBalance());
        toCoinAmountInfo.setAsset(new BigDecimal(toCoinAmountInfo.getAsset()).add(transferAmount) + "");
        toCoinAmountInfo.setBalance(toCoinAmount.add(transferAmount).toString());
        toCoinAmountInfo.setUpdateTime(new Date());
        userWalletService.updateWallet(toCoinAmountInfo);

        //发送短信
        String content_To ;
        messageService.insertUserMessage(from, "转账", "您转出一笔"+coinType+" 额度为:", amount,coinType,"0");
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" "+from+":转出一笔"+coinType+",到:"+to+"  额度为:"+amount+" 手续费为:"+serviceCharge);
//        System.out.println(from+","+"转出一笔SSSP,到,"+to+" 额度为:"+amount+","+"手续费为:"+serviceCharge+"");
        //新增一条发送收益消息
        messageService.insertUserMessage(from, "转账", "您转出一笔"+coinType+" 手续费为:", serviceCharge.toString(),coinType,"0");
        if (StringUtils.isNotEmpty(receivePhone)) {
            content_To = "账户(ID:" + to + ")在" + dateStr + "收到转账" + amount + coinType +"，请登录系统查看。";
            userService.sendVerificationCodeToTelphone(URLEncoder.encode(content_To, "UTF-8"), "JUSTSend", receivePhone, "", "", "", "");
        }
        messageService.insertUserMessage(to, "转账", "您有一笔"+coinType+"转入额度为:", amount,coinType,"1");
        return record;
    }

    @Transactional(rollbackFor = Exception.class)
    public UserWallet inqueryLockedCoinAmount(String userId, String coinType) throws BdexGatewayException {
        UserWallet userWallet = walletMapper.inqueryLockedCoinAmount(userId, coinType);
        if (userWallet == null) {
            throw new BdexGatewayException("查询比特包失败!");
        }
        return userWallet;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void rechangeCoin(String adminId, UserWallet refereeWallet, BigDecimal rechangeNum,String telhphone, String coinType) throws BdexGatewayException, UnsupportedEncodingException {
        if(rechangeNum.compareTo(new BigDecimal("0"))<0){
            throw new BdexGatewayException("充值金额不能为0!");
        }
        String userId = refereeWallet.getUserId();
        //更新充值方代币的数量
        refereeWallet.setBalance(new BigDecimal(refereeWallet.getBalance()).add(rechangeNum).setScale(6, BigDecimal.ROUND_HALF_DOWN)+"");
        refereeWallet.setAsset(new BigDecimal(refereeWallet.getAsset()).add(rechangeNum).setScale(6, BigDecimal.ROUND_HALF_DOWN)+"");
        refereeWallet.setUpdateTime(new Date());
        userWalletService.updateWalletCoinAmount(refereeWallet);
        //新增一条发送收益消息
        messageService.insertUserMessage(userId, "充值", "您收到一笔充值额度:", rechangeNum.toString(),coinType,"1");
        //修改矿池
        if(Constant.COINTYPE_SSSP.equals(coinType)){
            sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT, rechangeNum.multiply(BigDecimal.valueOf(-1)).toString(), userId);
        }else if(Constant.COINTYPE_TEX.equals(coinType)){
            sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT_TEX, rechangeNum.multiply(BigDecimal.valueOf(-1)).toString(), userId);
        }else{
            throw new BdexGatewayException("充值代币类型错误!");
        }

        //短信通知
//        if(StringUtils.isNotEmpty(telhphone)){
//            String dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//            String content_To = "账户(ID:" + userId + ")在" + dateTime + "充值" + rechangeNum +coinType+"，请登录系统查看。";
//            userService.sendVerificationCodeToTelphone(URLEncoder.encode(content_To, "UTF-8"), "JUSTSend", telhphone, "", "", "", "");
//        }
    }

    //锁仓
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, String> lockPosition(String userId,String coinType, String amount, String secPassword) throws BdexGatewayException {
        SysConfig smallMinerConfig = sysConfigMapper.selectByCode(Constant.smallMiner);
        SysConfig texSmallMinerConfig = sysConfigMapper.selectByCode(Constant.texSmallMiner);
        SysConfig strongMiningRewardPercentConfig = sysConfigMapper.selectByCode(Constant.strongMiningRewardPercent);
        SysConfig texStrongMiningRewardPercentConfig = sysConfigMapper.selectByCode(Constant.texStrongMiningRewardPercent);
        if (StringUtils.isEmpty(secPassword)) {
            throw new BdexGatewayException("交易密码不能为空!");
        }
        Map<String, String> resultMap = null;
        UserWallet wallet = new UserWallet();
        if(Constant.COINTYPE_SSSP.equals(coinType)){
            wallet = walletMapper.inqueryLockedCoinAmount(userId, Constant.COINTYPE_SSSP);
        }else if(Constant.COINTYPE_TEX.equals(coinType)){
            wallet = walletMapper.inqueryLockedCoinAmount(userId, Constant.COINTYPE_TEX);
        }else{
            throw new BdexGatewayException("锁仓代币类型错误!");
        }
        BigDecimal lockAmount = new BigDecimal(amount);
        BigDecimal userBalanceOfTex = new BigDecimal(wallet.getBalance());
        //判断锁仓是否足够
        if (lockAmount.compareTo(userBalanceOfTex) > 0) {
            throw new BdexGatewayException(coinType+"余额不足，请确认!");
        }
        BigDecimal giftAmount;
        if(Constant.COINTYPE_SSSP.equals(coinType)){
            if (lockAmount.compareTo(new BigDecimal(smallMinerConfig.getInitValue())) < 0) {
                throw new BdexGatewayException("至少需要"+smallMinerConfig.getInitValue()+"个"+coinType+"进行锁仓,请确认!");
            }
            //计算用户锁仓赠送5%
            giftAmount = lockAmount.multiply(new BigDecimal(strongMiningRewardPercentConfig.getInitValue())).setScale(6, BigDecimal.ROUND_HALF_DOWN);
        }else{
            if (lockAmount.compareTo(new BigDecimal(texSmallMinerConfig.getInitValue())) < 0) {
                throw new BdexGatewayException("至少需要"+texSmallMinerConfig.getInitValue()+"个"+coinType+"进行锁仓,请确认!");
            }
            //计算用户锁仓赠送5%
            giftAmount = lockAmount.multiply(new BigDecimal(texStrongMiningRewardPercentConfig.getInitValue())).setScale(6, BigDecimal.ROUND_HALF_DOWN);
        }
        //更新用户锁仓
        userWalletService.lockSSPReward(wallet, lockAmount, giftAmount,coinType);

        //更新充值记录
        lotteryService.updatePoint(wallet.getUserId(), lockAmount + "",coinType);
        //查找用户的推荐人
        User referee = refereeService.userReferee(wallet.getUserId());
        if(referee != null) {
            //推荐人比特宝
            UserWallet userWallet = userWalletMapper.inqueryLockedCoinAmount(referee.getId(), coinType);
            //余额
            BigDecimal balance = new BigDecimal(userWallet.getBalance());
            //赠送存币的百分之十
            BigDecimal lockAmountNum1 = new BigDecimal("0");
            if(Constant.COINTYPE_SSSP.equals(coinType)){
                SysConfig releaseReferee1AvailableBalanceConfig = sysConfigMapper.selectByCode(Constant.releaseReferee1AvailableBalance);
                lockAmountNum1 = new BigDecimal(releaseReferee1AvailableBalanceConfig.getInitValue()).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
            }else if(Constant.COINTYPE_TEX.equals(coinType)){
                SysConfig releaseReferee1TexAvailableBalanceConfig = sysConfigMapper.selectByCode(Constant.releaseReferee1TexAvailableBalance);
                lockAmountNum1 = new BigDecimal(releaseReferee1TexAvailableBalanceConfig.getInitValue()).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
            }else {
                throw new BdexGatewayException("代币种类错误!");
            }
            balance = balance.add(lockAmountNum1);
            //更新比特宝
            userWallet.setBalance(balance + "");
            userWallet.setAsset(lockAmountNum1.add(new BigDecimal(userWallet.getAsset())) + "");
            userWallet.setUpdateTime(new Date());
            int result = userWalletMapper.updateWalletCoinAmount(userWallet);
            if (result <= 0) {
                throw new BdexGatewayException("更新钱包失败!");
            }
            //新增一条奖励消息
            messageService.insertUserMessage(referee.getId(), "推荐人奖励", "您推荐人锁仓后的奖励，奖励"+coinType+":", lockAmountNum1.toString(), coinType,"1");
            //修改矿池
            if(Constant.COINTYPE_TEX.equals(coinType)){
                sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT_TEX, lockAmountNum1.multiply(BigDecimal.valueOf(-1)).toString(), referee.getId());
            }else if(Constant.COINTYPE_SSSP.equals(coinType)){
                sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT, lockAmountNum1.multiply(BigDecimal.valueOf(-1)).toString(), referee.getId());
            }else {
                throw new BdexGatewayException("代币种类错误!");
            }

            //释放推荐人当前锁仓的10%,如果锁仓不足，则释放糖果
        	userWalletService.releaseSSPRefereeReward(referee, lockAmount,coinType);
            User user2 = refereeService.userReferee(referee.getId());
            if(user2!=null){
                //推荐人id
                //推荐人比特宝
                UserWallet userWallet1 = userWalletMapper.inqueryLockedCoinAmount(user2.getId(), coinType);
                //余额
                BigDecimal balance1 = new BigDecimal(userWallet1.getBalance());
                BigDecimal lockAmountNum2 = new BigDecimal("0");
                //赠送存币的百分之五
                if(Constant.COINTYPE_SSSP.equals(coinType)){
                    SysConfig releaseReferee2AvailableBalanceConfig = sysConfigMapper.selectByCode(Constant.releaseReferee2AvailableBalance);
                    lockAmountNum2 = new BigDecimal(releaseReferee2AvailableBalanceConfig.getInitValue()).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
                }else{
                    SysConfig releaseReferee2TexAvailableBalanceConfig = sysConfigMapper.selectByCode(Constant.releaseReferee2TexAvailableBalance);
                    lockAmountNum2 = new BigDecimal(releaseReferee2TexAvailableBalanceConfig.getInitValue()).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
                }
                balance1 = balance1.add(lockAmountNum2);
                //更新比特宝
                userWallet1.setBalance(balance1 + "");
                userWallet1.setAsset(lockAmountNum2.add(new BigDecimal(userWallet1.getAsset())) + "");
                userWallet1.setUpdateTime(new Date());
                int result2 = userWalletMapper.updateWalletCoinAmount(userWallet1);
                if (result2 <= 0) {
                    throw new BdexGatewayException("更新钱包失败!");
                }
                //新增一条奖励消息
                messageService.insertUserMessage(user2.getId(),
                        "推荐人奖励", "您推荐人锁仓后的奖励，奖励"+coinType+":", lockAmountNum2.toString(), coinType,"1");
                //修改矿池
                if(Constant.COINTYPE_SSSP.equals(coinType)){
                    sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT, lockAmountNum2.multiply(BigDecimal.valueOf(-1)).toString(), referee.getId());
                }else{
                    sysConfigService.changeConfigValue(ConfigParam.MINER_POOL_AMOUNT_TEX, lockAmountNum2.multiply(BigDecimal.valueOf(-1)).toString(), referee.getId());
                }
                //释放推荐人当前锁仓的10%,如果锁仓不足，则释放糖果
                userWalletService.releaseSSPRefereeReward(user2, lockAmount,coinType);
            }
        }
        resultMap = new HashMap<String, String>();
        resultMap.put("lockCoinNum", lockAmount + "");
        resultMap.put("lockreward", giftAmount + "");
        resultMap.put("lockCoinNumTotal", giftAmount.add(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN) + "");
        resultMap.put("coinType",coinType);
        if(Constant.COINTYPE_SSSP.equals(coinType)){
            SysConfig releaseCoinPercentageConfig = sysConfigMapper.selectByCode(Constant.releaseCoinPercentage);
            resultMap.put("info", "锁仓存入的" + giftAmount.add(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN) + Constant.COINTYPE_SSSP + "每天释放"+releaseCoinPercentageConfig.getInitValue()+"到您的可用余额中，直至释放完为止!");
        }else{
            SysConfig releaseTexCoinPercentageConfig = sysConfigMapper.selectByCode(Constant.releaseTexCoinPercentage);
            resultMap.put("info", "锁仓存入的" + giftAmount.add(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN) + coinType + "每天释放"+releaseTexCoinPercentageConfig.getInitValue()+"到您的可用余额中，直至释放完为止!");
        }
        return resultMap;
    }

    /*private Map<String, String> lockCoinCheck(BigDecimal lockAmount, BigDecimal giftAmount, UserWallet wallet) throws BdexGatewayException {
        Map<String, String> resultMap = new HashMap<String, String>();
        //查看其一级推荐人和二级推荐人
        User user1 = refereeService.userReferee(wallet.getUserId());
        if (user1 != null) {
            //一级推荐人释放锁仓
            //推荐人释放将要锁仓的ssp的10%【如果锁仓总的小于等于10%分量则释放全部】
            BigDecimal lockAmountNum = new BigDecimal(Constant.releaseReferee1AvailableBalance).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
            userWalletService.releaseSSPRefereeReward(user1, lockAmountNum);
            User user2 = refereeService.userReferee(user1.getId());
            if (user2 != null) {
                BigDecimal lockAmountNum1 = new BigDecimal(Constant.releaseReferee2AvailableBalance).multiply(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN);
                //二级推荐人释放锁仓
                userWalletService.releaseSSPRefereeReward(user2, lockAmountNum1);
            }
        }
        //更新充值记录
        lotteryService.updatePoint(wallet.getUserId(), lockAmount + "", Constant.COINTYPE_SSSP);
        //扣除可用额度划入锁仓
        userWalletService.lockSSPReward(wallet, lockAmount, giftAmount);
        resultMap.put("lockCoinNum", lockAmount + "");
        resultMap.put("lockreward", giftAmount + "");
        resultMap.put("lockCoinNumTotal", giftAmount.add(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN) + "");
        resultMap.put("coinType", Constant.COINTYPE_SSSP);
        resultMap.put("info", "锁仓存入的" + giftAmount.add(lockAmount).setScale(6, BigDecimal.ROUND_HALF_DOWN) + Constant.COINTYPE_SSSP + "每天释放千分之五到您的可用余额中，直至释放完为止!");
        return resultMap;
    }*/

    @Transactional(readOnly = true)
    @Override
    public Page<TransferRecords> pageData(String userId, String coinType) throws BdexGatewayException {
        return transferRecordsMapper.pageData(userId, coinType);
    }

    @Transactional(readOnly = true)
    @Override
    public TransferRecordsDTO queryTransferDetail(Integer transactionId) throws BdexGatewayException {
        TransferRecords record = transferRecordsMapper.selectByPrimaryKey(transactionId);
        TransferRecordsDTO result = new TransferRecordsDTO(record);
        User user = null;
        if (record.getFromUser() != null) {
            String nickName = redisUtil.hget(User.class.getName() + ".nickName", record.getFromUser());
            if (nickName == null) {
                user = userService.getById(record.getFromUser());
                if (user != null) {
                    nickName = user.getNickName();
                    redisUtil.hset(User.class.getName() + ".nickName", record.getFromUser(), nickName);
                }
            }
            result.setFromUserNickName(nickName);
        }
        if (record.getToUser() != null) {
            String nickName = redisUtil.hget(User.class.getName() + ".nickName", record.getToUser());
            if (nickName == null) {
                user = userService.getById(record.getToUser());
                if (user != null) {
                    nickName = user.getNickName();
                    redisUtil.hset(User.class.getName() + ".nickName", record.getToUser(), nickName);
                }
            }
            result.setToUserNickName(nickName);
        }
        return result;
    }
}
